﻿import D3.Matrix;
import D3.Polygon;
import D3.ProjectTranceCallBack;
dynamic class D3.Vertex extends Matrix {
	private static var VertexCounts:Number = 0;
	public static function get NewVertexIndex():Number {
		return VertexCounts++;
	}
	
	private var $vertexName:String;
	private var $parent:Polygon;
	private var $mc:MovieClip;
	private var $pVertex:Vertex;
	
	private var $ax:Number;
	private var $ay:Number;
	private var $az:Number;
	
	private var $deadPoint:Number = -500;
	public function get DeadPoint():Number {
		return this.$deadPoint;
	}
	public function set DeadPoint(value:Number) {
		this.$deadPoint = value;
	}
	
	/**
	 * bingding Vertex with Movieclip 外挂用于创建Vertex图形的mc
	 */
	public function get MC():MovieClip{
		return this.$mc;
	}
	/**
	 * bingding Vertex with Movieclip 外挂用于创建Vertex图形的mc
	 */
	public function set MC(value:MovieClip){
		this.$mc=value;
	}
	/**
	 * 返回该点所在的Polygon
	 */
	public function get Parent():Polygon{
		return this.$parent;
	}
	/**
	 * 返回该点所在的Polygon
	 */
	public function set Parent(value:Polygon){
		this.$parent=value;
	}
	/**
	 * 该点与z/y平面的夹角
	 */
	public function get AngleX():Number{
		return Math.asin(this.matrixArray[0][0]/this.Distance);
	}
	/**
	 * 该点与x/z平面的夹角
	 */
	public function get AngleY():Number{
		return Math.asin(this.matrixArray[0][1]/this.Distance);
	}
	/**
	 * 该点与y/x平面的夹角
	 */
	public function get AngleZ():Number{
		return Math.asin(this.matrixArray[0][2]/this.Distance);
	}
	/**
	 * 点到该坐标系中心位置距离
	 */
	public function get Distance():Number{
		return this.getDistance();
	}
	/**
	 * 点到该坐标系中心位置距离
	 */
	public function set Distance(value:Number){
		var xx=Math.sin(this.AngleX)*value;
		var yy=Math.sin(this.AngleY)*value;
		var zz=Math.sin(this.AngleZ)*value;
		this.matrixArray[0][0]=xx;
		this.matrixArray[0][1]=yy;
		this.matrixArray[0][2]=zz;
	}
	/**
	 * 投影到屏幕后的_X属性值
	 */
	public function get x():Number {
		return this.matrixArray[0][0]*(_Z-this.$deadPoint)/this.$deadPoint;
	}
	
	
	/**
	 * 投影到屏幕后的_Y属性值
	 */
	public function get y():Number {
		return this.matrixArray[0][1]*(_Z-this.$deadPoint)/this.$deadPoint;
	}
	
	
	/**
	 * 投影到屏幕后的_Z属性值
	 */
	public function get z():Number {
		return this.matrixArray[0][2];
	}
	
	
	/**
	 * 3维空间中的点
	 * @param	vertexName 点唯一标识名
	 * @param	x
	 * @param	y
	 * @param	z
	 */
	public function Vertex(vertexName:String,x:Number,y:Number,z:Number){
		if(x==undefined)
		{
			x=0;
		}
		if(y==undefined){
			y=0;
		}
		if(z==undefined){
			z=0;
		}
		this.matrixArray=[[x,y,z,1]];
		
		if(vertexName=="" || vertexName==undefined)
		{vertexName="P"+NewVertexIndex;}
		this.$vertexName=vertexName;
	}
	private function getDistance(x:Number,y:Number,z:Number){
		if(arguments.length==0){
			x=this._X;
			y=this._Y;
			z=this._Z;
		}else{
			x=((x==undefined)? 0:x);
			y=((y==undefined)? 0:y);
			z=((z==undefined)? 0:z);
		}
		return Math.sqrt(x*x+y*y+z*z); 
	}
	//project this and sub point to View
	public function ProjectAndSetMC():Vertex{
		var lv:Vertex;
		if(this.$mc!=undefined){
			lv=getLocationInParentAxes(this);
			D3.ProjectTranceCallBack.ProjectMcInvoke(this,lv,this.$mc);
		}
		return lv;
	}
	
	private function getLocationInParentAxes(I:Object):Vertex{
		var v:Vertex;
		if(I.PolygonName!=null){
			v=Polygon(I).CenterVertex;
		}else if(I.VertexName!=null){
			v=Vertex(I);
		}else{
			trace("this argument's structure is not match:"+I);
		}
		if(I.Parent!=undefined){
			var tm:Matrix=getTM(I.Parent);
			var vrs:Vertex=getLocationInParentAxes(I.Parent);
			v= v.X(tm).GetMove(vrs._X,vrs._Y,vrs._Z);
		}else{
			v= v;
		}
		if(I.PolygonName!=null){
			Polygon(I).CenterVertex.$pVertex=v;
		}else if(I.VertexName!=null){
			Vertex(I).$pVertex=v;
		}else{
			trace("this argument's structure is not match:"+I);
		}
		return v;
	}
	private function getTM(I:Object):Matrix{
		if(I.AxesTranceMatrix==undefined) {
			trace("this Vertex or Polygon is not in an screen:"+I);
		}
		if(I.Parent!=undefined){
			return Matrix(I.AxesTranceMatrix).X(getTM(I.Parent));
		}else{
			return Matrix(I.AxesTranceMatrix);
		}
	}
	
	
	
	// Matrix multiplicate
	public function X(tranceMatrix:Matrix):Vertex{
		if(tranceMatrix==undefined)
		{
			return this;
		}
		if( tranceMatrix.matrixArray.length != 4)
		{
			Say("the tranceMatrix's structure is not match!");
			return null;
		}
		var m:Matrix=Matrix.MatrixX(this,tranceMatrix);
		return new Vertex(this.VertexName,m.matrixArray[0][0],m.matrixArray[0][1],m.matrixArray[0][2]);
	}
	///Matrix rotate this in parent screen on X-Axes rotate
	public function XRotation(O:Number):Matrix{
		var tm:Matrix=Matrix.getXRotation(O);
		if(tm!=null){
			var cpV:Vertex=this.X(tm);
			this.matrixArray=cpV.matrixArray;
		}
		return tm;
	}
	///Matrix rotate this in parent screen on Y-Axes rotate
	public function YRotation(O:Number):Matrix{
		var tm:Matrix=Matrix.getYRotation(O);
		if(tm!=null){
			var cpV:Vertex=this.X(tm);
			this.matrixArray=cpV.matrixArray;
		}
		return tm;
	}
	///Matrix rotate this in parent screen on Z-Axes rotate
	public function ZRotation(O:Number):Matrix{
		var tm:Matrix=Matrix.getZRotation(O);
		if(tm!=null){
			var cpV:Vertex=this.X(tm);
			this.matrixArray=cpV.matrixArray;
		}
		return tm;
	}
	///Matrix rotate this in parent screen on Free-Axes rotate
	public function FreeRotation(x:Object,y:Number,z:Number,O:Number):Matrix{
		var tm:Matrix=null;
		if(x.matrixArray!=undefined)
		{
			var cpV:Vertex=this.X(Matrix(x));
			this.matrixArray=cpV.matrixArray;
		}else if(typeof(x)=="number"){
			tm=Matrix.getFreeAxisRotation(Number(x),y,z,O);
			if(tm!=null){
				var cpV:Vertex=this.X(tm);
				this.matrixArray=cpV.matrixArray;
			}
		}else{
			Say("the argument's type is not match["+arguments+"]");
		}
		return tm;
	}
	public function MoveTo(x:Number,y:Number,z:Number){
		if(x==undefined||y==undefined||z==undefined) {
			Say(this.VertexName+": [moveto]the arguemnt's field can't be empty or null["+arguments+"]");
		}
		this.matrixArray[0][0]=x;
		this.matrixArray[0][1]=y;
		this.matrixArray[0][2]=z;
	}
	public function Move(x:Number,y:Number,z:Number){
		if(x==undefined) x=0;
		if(y==undefined) y=0;
		if(z==undefined) z=0;
		this.matrixArray[0][0]+=x;
		this.matrixArray[0][1]+=y;
		this.matrixArray[0][2]+=z;
	}
	
	///Matrix get copy of vertex after X-Axes rotate
	public function GetXRotation(O:Number):Vertex{
		var tm:Matrix=Matrix.getXRotation(O);
		if(tm!=null){
			var cpV:Vertex=this.X(tm);
			cpV.VertexName="Copy"+this.VertexName;
			return cpV
		}
		return null;
	}
	///Matrix get copy of vertex after Y-Axes rotate
	public function GetYRotation(O:Number):Vertex{
		var tm:Matrix=Matrix.getZRotation(O);
		if(tm!=null){
			var cpV:Vertex=this.X(tm);
			cpV.VertexName="Copy"+this.VertexName;
			return cpV
		}
		return null;
	}
	///Matrix get copy of vertex after Z-Axes rotate
	public function GetZRotation(O:Number):Vertex{
		var tm:Matrix=Matrix.getZRotation(O);
		if(tm!=null){
			var cpV:Vertex=this.X(tm);
			cpV.VertexName="Copy"+this.VertexName;
			return cpV
		}
		return null;
	}
	///Matrix get copy of vertex after Free-Axes rotate
	public function GetFreeRotation(x:Number,y:Number,z:Number,O:Number):Vertex{
		var tm:Matrix=Matrix.getFreeAxisRotation(x,y,z,O);
		if(tm!=null){
			var cpV:Vertex=this.X(tm);
			cpV.VertexName="Copy"+this.VertexName;
			return cpV
		}
		return null;
	}
	///get copy of vertex after move
	public function GetMove(x:Number,y:Number,z:Number):Vertex{
		if(x==undefined) x=0;
		if(y==undefined) y=0;
		if(z==undefined) z=0;
		return new Vertex("Copy"+this.VertexName,this.matrixArray[0][0]+x,this.matrixArray[0][1]+y,this.matrixArray[0][2]+z);
	}
	
	
	public function get PVertex():Vertex{
		return this.$pVertex;
	}
	public function set PVertex(pv:Vertex){
		this.$pVertex=pv;
	}
	
	public function get _X():Number{
		return this.matrixArray[0][0];
	}
	public function get _Y():Number{
		return this.matrixArray[0][1];
	}
	public function get _Z():Number{
		return this.matrixArray[0][2];
	}
	
	public function get VertexName():String{
		return this.$vertexName;
	}
	public function set VertexName(vertexName:String){
		this.$vertexName=vertexName;
	}
	public function toString() {
		if(arguments[0]=="point"){
			return this.$vertexName + "(" + this._X + "," + this._Y + "," + this._Z + ")";
		}else {
			return this.$vertexName;
		}
	}
}